package com.zwh.se.collection.iterator_iterable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;

/**
 * @author yexi
 * 经典面试题: iterator(),Iterator,Iterable的区别和关系
 * <p>
 * 此包算是对迭代器这一存在的精讲
 */
public class IterableDemo {
    public static void main(String[] args) {
        //以ArrayList为例,其对应的关系:
        // ArrayList implements List接口 extends Collection接口 extends Iterable接口
        /**
         * 而在这个 Iterable 接口里面就存在这么一个抽象方法 iterator()。抽象方法要在具体实现类中得到实现。
         * @see Iterable#iterator()——定义为:返回一个迭代器用于遍历元素
         * 于是
         * @see ArrayList#iterator()——实现为:返回一个以固定顺序返回此列表中元素的迭代器。
         *                该迭代器是 fail-fast 的(集合的一种错误机制,当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件)。
         * 而这个 iterator() 方法的返回值,就是一个 Iterator (也就是迭代器）
         * @see ArrayList.Itr implements Iterator<E> 是ArrayList的私有的一个实现了Iterator接口的内部类
         */
        ArrayList arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "a", "b", "c", "d", "e", "g", "h");
        /**
         * @see Iterator#hasNext() 抽象方法。如果迭代中还有元素的话则返回true。(换句话说，如果next()方法将返回一个元素而不是抛出异常则返回true)
         * @see Iterator#next() 抽象方法。返回迭代中的下一个元素。
         * 那么这两个抽象方法的具体实现就在
         * @see ArrayList.Itr implements Iterator<E> 里面
         * @see ArrayList.Itr#cursor        模拟指针。代表下一个将返回的元素的索引。
         * @see ArrayList.Itr#lastRet = -1  最后一个返回元素的索引。-1为默认值,-1时代表没有要返回的。
         * @see ArrayList.Itr#expectedModCount = modCount  期望修改次数。默认值是当前集合的实际修改次数(通过该字段判断是否发生了并发修改)
         * @see ArrayList#modCount 对当前集合的实际修改次数
         *                        (查看ArrayList的add()和remove()方法就可以发现,每次调用add()方法或者remove()方法,modCount都会+1)
         */
        Iterator iterator = arrayList.iterator();
        /**
         * @see ArrayList.Itr#hasNext()
         *          return cursor != size;  只要当前模拟指针不等于集合内的元素数量,就认为有下一个元素可以迭代
         */
        while (iterator.hasNext()) {
            /**
             * @see ArrayList.Itr#next()
             * {
             *        checkForComodification();
             *        int i = cursor;                                      //模拟出当前指针指向的元素位置
             *        if (i >= size) throw new NoSuchElementException();   //如果cursor>size则抛异常
             *        Object[] elementData = ArrayList.this.elementData;   //底层存储数组
             *        if (i >= elementData.length)
             *            throw new ConcurrentModificationException();     //当模拟指针>=底层存储数组时,抛出并发修改异常
             *        cursor = i + 1;                                      //改变cursor来模拟改变指针
             *        return (E) elementData[lastRet = i];                 //调整最后一个返回元素的索引,正常迭代的话就会是从0开始
             *    }
             *
             * @see ArrayList.Itr#checkForComodification()
             * {
             *    if (modCount != expectedModCount)                   //如果 实际修改次数 != 期望修改次数 的话,则认为发生了
             *      throw new ConcurrentModificationException();      并发修改动作,抛出并发修改异常(这就是所谓的 fail-fast 机制)
             * }
             */
            Object nextItem = null;
            try {
                nextItem = iterator.next();
            } catch (ConcurrentModificationException e) {
                System.out.println("\033[31;4m" + e + "\033[0m");
                break;
            }
            if (nextItem.equals("d")) {
                //而从上面分析得知当调用add()或remove()时会对modCount进行修改,从而导致迭代器发生并发修改异常。

                //也就是说,修改的话是就不会触发的
                int index = arrayList.indexOf("d");
                arrayList.set(index + 1, "f");//测试demo,故意修改后一个元素为c,让.equals(
            }
            if (nextItem.equals("f")) {
                //为了防止对modCount进行修改导致并发修改异常,在使用迭代器时,万万不可调用list本身的移动元素方法(这里是测试demo,随便浪)
                arrayList.remove("h");
                arrayList.add("h");
            }
            if (nextItem.equals("b")) {
                /**
                 * 如果真的要在迭代器做删除,就只能使用迭代器自带的 iterator.remove() 方法了
                 * @see ArrayList.Itr#remove()
                 * {
                 *     checkForComodification();  //检验 modCount != expectedModCount
                 *     try {
                 *          ArrayList.this.remove(lastRet);  //本质上依旧是调用了list自己的remove
                 *          cursor = lastRet;      //调整模拟指针位置指向最后一个返回元素的位置(一般是回到删除元素的前一个元素位置)
                 *          lastRet = -1;          //定义现在不存在最后一个返回元素
                 *          expectedModCount = modCount;   //重点。将当前集合的实际修改次数赋值给期望修改次数
                 *     } catch (IndexOutOfBoundsException ex) {
                 *         // 捕获到索引越界异常时抛出并发修改异常,触发条件不明
                 *         throw new ConcurrentModificationException();
                 *     }
                 * }
                 */
                iterator.remove();
                iterator.next();
            }
        }
        System.out.println(arrayList);

        //增强for循环,其底层也是通过迭代器实现的(自行打断点)
        try {
            for (Object o : arrayList) {
                //最好的证明方法
                arrayList.remove("h");
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("\033[31;4m" + e + "\033[0m");
        }

        System.out.println(arrayList);

    }
}
